using System;
using System.Collections.Generic;

namespace Flit.Samples.StateMachine
{
    #region Designer generated code
    public partial class TurnstileStateMachine
    {
        private bool blockSignals;
        private Action<Signal> currentState;
        private Dictionary<State, Action<Signal>> statesToDelegates;
        private Dictionary<Action<Signal>, State> delegateToStates;

        public TurnstileStateMachine(State initialState)
        {
            statesToDelegates = new Dictionary<State, Action<Signal>>()
            {
                { State.Locked, __Locked },
                { State.Unlocked, __Unlocked },
                { State.Violation, __Violation },
            };

            delegateToStates = new Dictionary<Action<Signal>, State>()
            {
                { __Locked, State.Locked },
                { __Unlocked, State.Unlocked },
                { __Violation, State.Violation },
            };

            currentState = statesToDelegates[initialState];
        }

        public State CurrentState
        {
            get
            {
                return delegateToStates[currentState];
            }
        }

        public void Accept(Signal signal)
        {
            currentState(signal);
        }

        private void __Locked(Signal signal)
        {
            if(blockSignals)
            {
                throw new InvalidOperationException("You can't send signals to this state machine while it's changing states.");
            }

            switch(signal)
            {
                case Signal.Coin:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Locked(State.Unlocked, Signal.Coin, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Locked_To_Unlocked_Via_Coin(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Unlocked(State.Locked, Signal.Coin, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Locked, Signal.Coin, State.Unlocked, ref cancel);
                        if(cancel) return;

                        currentState = __Unlocked;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Locked(State.Unlocked, Signal.Coin);
                    OnStateChangedFrom_Locked_To_Unlocked_Via_Coin();
                    OnStateEntered_Unlocked(State.Locked, Signal.Coin);
                    OnStateChanged(State.Locked, Signal.Coin, State.Unlocked);
                    break;

                case Signal.Pass:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Locked(State.Violation, Signal.Pass, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Locked_To_Violation_Via_Pass(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Violation(State.Locked, Signal.Pass, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Locked, Signal.Pass, State.Violation, ref cancel);
                        if(cancel) return;

                        currentState = __Violation;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Locked(State.Violation, Signal.Pass);
                    OnStateChangedFrom_Locked_To_Violation_Via_Pass();
                    OnStateEntered_Violation(State.Locked, Signal.Pass);
                    OnStateChanged(State.Locked, Signal.Pass, State.Violation);
                    break;

                default:
                    string message = "Unexpected signal ("+signal+") received, expected one of: Coin, Pass.";
                    throw new UnexpectedSignalException(message);
            }
        }

        private void __Unlocked(Signal signal)
        {
            if(blockSignals)
            {
                throw new InvalidOperationException("You can't send signals to this state machine while it's changing states.");
            }

            switch(signal)
            {
                case Signal.Pass:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Unlocked(State.Locked, Signal.Pass, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Unlocked_To_Locked_Via_Pass(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Locked(State.Unlocked, Signal.Pass, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Unlocked, Signal.Pass, State.Locked, ref cancel);
                        if(cancel) return;

                        currentState = __Locked;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Unlocked(State.Locked, Signal.Pass);
                    OnStateChangedFrom_Unlocked_To_Locked_Via_Pass();
                    OnStateEntered_Locked(State.Unlocked, Signal.Pass);
                    OnStateChanged(State.Unlocked, Signal.Pass, State.Locked);
                    break;

                case Signal.Coin:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Unlocked(State.Unlocked, Signal.Coin, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Unlocked_To_Unlocked_Via_Coin(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Unlocked(State.Unlocked, Signal.Coin, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Unlocked, Signal.Coin, State.Unlocked, ref cancel);
                        if(cancel) return;

                        currentState = __Unlocked;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Unlocked(State.Unlocked, Signal.Coin);
                    OnStateChangedFrom_Unlocked_To_Unlocked_Via_Coin();
                    OnStateEntered_Unlocked(State.Unlocked, Signal.Coin);
                    OnStateChanged(State.Unlocked, Signal.Coin, State.Unlocked);
                    break;

                default:
                    string message = "Unexpected signal ("+signal+") received, expected one of: Pass, Coin.";
                    throw new UnexpectedSignalException(message);
            }
        }

        private void __Violation(Signal signal)
        {
            if(blockSignals)
            {
                throw new InvalidOperationException("You can't send signals to this state machine while it's changing states.");
            }

            switch(signal)
            {
                case Signal.Reset:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Violation(State.Locked, Signal.Reset, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Violation_To_Locked_Via_Reset(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Locked(State.Violation, Signal.Reset, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Violation, Signal.Reset, State.Locked, ref cancel);
                        if(cancel) return;

                        currentState = __Locked;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Violation(State.Locked, Signal.Reset);
                    OnStateChangedFrom_Violation_To_Locked_Via_Reset();
                    OnStateEntered_Locked(State.Violation, Signal.Reset);
                    OnStateChanged(State.Violation, Signal.Reset, State.Locked);
                    break;

                case Signal.Pass:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Violation(State.Violation, Signal.Pass, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Violation_To_Violation_Via_Pass(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Violation(State.Violation, Signal.Pass, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Violation, Signal.Pass, State.Violation, ref cancel);
                        if(cancel) return;

                        currentState = __Violation;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Violation(State.Violation, Signal.Pass);
                    OnStateChangedFrom_Violation_To_Violation_Via_Pass();
                    OnStateEntered_Violation(State.Violation, Signal.Pass);
                    OnStateChanged(State.Violation, Signal.Pass, State.Violation);
                    break;

                case Signal.Coin:

                    blockSignals = true;

                    try
                    {
                        bool cancel = false;
                        OnStateLeaving_Violation(State.Violation, Signal.Coin, ref cancel);
                        if(cancel) return;
                        OnStateChangingFrom_Violation_To_Violation_Via_Coin(ref cancel);
                        if(cancel) return;
                        OnStateEntering_Violation(State.Violation, Signal.Coin, ref cancel);
                        if(cancel) return;
                        OnStateChanging(State.Violation, Signal.Coin, State.Violation, ref cancel);
                        if(cancel) return;

                        currentState = __Violation;
                    }
                    finally
                    {
                        blockSignals = false;
                    }
                    OnStateLeft_Violation(State.Violation, Signal.Coin);
                    OnStateChangedFrom_Violation_To_Violation_Via_Coin();
                    OnStateEntered_Violation(State.Violation, Signal.Coin);
                    OnStateChanged(State.Violation, Signal.Coin, State.Violation);
                    break;

                default:
                    string message = "Unexpected signal ("+signal+") received, expected one of: Reset, Pass, Coin.";
                    throw new UnexpectedSignalException(message);
            }
        }

        partial void OnStateChangedFrom_Locked_To_Unlocked_Via_Coin();
        partial void OnStateChangedFrom_Locked_To_Violation_Via_Pass();
        partial void OnStateChangedFrom_Unlocked_To_Locked_Via_Pass();
        partial void OnStateChangedFrom_Unlocked_To_Unlocked_Via_Coin();
        partial void OnStateChangedFrom_Violation_To_Locked_Via_Reset();
        partial void OnStateChangedFrom_Violation_To_Violation_Via_Coin();
        partial void OnStateChangedFrom_Violation_To_Violation_Via_Pass();
        partial void OnStateChangingFrom_Locked_To_Unlocked_Via_Coin(ref bool cancel);
        partial void OnStateChangingFrom_Locked_To_Violation_Via_Pass(ref bool cancel);
        partial void OnStateChangingFrom_Unlocked_To_Locked_Via_Pass(ref bool cancel);
        partial void OnStateChangingFrom_Unlocked_To_Unlocked_Via_Coin(ref bool cancel);
        partial void OnStateChangingFrom_Violation_To_Locked_Via_Reset(ref bool cancel);
        partial void OnStateChangingFrom_Violation_To_Violation_Via_Coin(ref bool cancel);
        partial void OnStateChangingFrom_Violation_To_Violation_Via_Pass(ref bool cancel);
        partial void OnStateEntered_Locked(State oldState, Signal signal);
        partial void OnStateEntered_Unlocked(State oldState, Signal signal);
        partial void OnStateEntered_Violation(State oldState, Signal signal);
        partial void OnStateEntering_Locked(State oldState, Signal signal, ref bool cancel);
        partial void OnStateEntering_Unlocked(State oldState, Signal signal, ref bool cancel);
        partial void OnStateEntering_Violation(State oldState, Signal signal, ref bool cancel);
        partial void OnStateLeaving_Locked(State newState, Signal signal, ref bool cancel);
        partial void OnStateLeaving_Unlocked(State newState, Signal signal, ref bool cancel);
        partial void OnStateLeaving_Violation(State newState, Signal signal, ref bool cancel);
        partial void OnStateLeft_Locked(State newState, Signal signal);
        partial void OnStateLeft_Unlocked(State newState, Signal signal);
        partial void OnStateLeft_Violation(State newState, Signal signal);

        partial void OnStateChanging(State oldState, Signal signal, State newState, ref bool cancel);
        partial void OnStateChanged(State oldState, Signal signal, State newState);

        public enum Signal
        {
            Coin,
            Pass,
            Reset,
        }

        public enum State
        {
            Locked,
            Unlocked,
            Violation,
        }
    }
    #endregion
}

